package com.acme.bankapp.domain.bank;

import com.acme.bankapp.exception.bank.NotEnoughFundsException;

import java.io.Serializable;


/**
 * Abstract implementation of Account, implementing main functionality.
 * Withdraw(...) method is based on abstract method maximumAmountToWithdraw().
 *
 */
public abstract class AbstractAccount implements Account, Serializable {

    private Client client;

    private double balance;

    /**
     * Creates Account with amount on balance
     * @param amount initial amount
     */
    public AbstractAccount(final double amount) {

        this.balance = amount;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Client getClient() {
        return client;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void setClient(Client client) {
        this.client = client;
    }

    /**
     * {@inheritDoc}
     */
    public double getBalance() {
        return balance;
    }

    protected void setBalance(double balance) {
        this.balance = balance;
    }
    /**
     * {@inheritDoc}
     */
    public double deposit(final double amount) throws  IllegalArgumentException{
        if(amount < 0){
            throw new IllegalArgumentException("Amount should be positive!");
        }
        balance += amount;
        return balance;
    }
    /**
     * {@inheritDoc}
     */
    public double withdraw(final double amount) throws NotEnoughFundsException, IllegalArgumentException {
        if(amount < 0){
            throw new IllegalArgumentException("Amount should be positive!");
        }
        if(amount > maximumAmountToWithdraw()){
            throw new NotEnoughFundsException(String.format("You tried to withdraw %s but you can only withdraw %s",amount,maximumAmountToWithdraw()));
        }else{
            balance -= amount;
            return balance;
        }
    }
    /**
     * {@inheritDoc}
     */
    public abstract double maximumAmountToWithdraw();

    @Override
    public long getDecimalBalance() {
        return Math.round(balance);
    }

    /**
     * @see Account#setClient(Client)
     * @param o Account to compare to
     * @return true if equals, false otherwise
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        AbstractAccount that = (AbstractAccount) o;

        if (Double.compare(that.balance, balance) != 0) return false;
        if (client != null ? !client.equals(that.client) : that.client != null) return false;

        return true;
    }

    /**
     * Returns hashCode of Account
     * @see Account#setClient(Client)
     * @return hashCode
     */
    @Override
    public int hashCode() {
        int result;
        long temp;
        result = client != null ? client.hashCode() : 0;
        temp = Double.doubleToLongBits(balance);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

}
